﻿using CodePlex.KeyedList;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using CodePlex.KeyedList.TestProject.TestObjects;

namespace CodePlex.KeyedList.TestProject
{

	/// <summary>
	///This is a test class for KeyedListTest and is intended
	///to contain all KeyedListTest Unit Tests
	///</summary>
	[TestClass()]
	public class KeyedListTest
	{

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext { get; set; }

		#region Additional test attributes
		// 
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		//[ClassInitialize()]
		//public static void MyClassInitialize(TestContext testContext)
		//{
		//}
		//
		//Use ClassCleanup to run code after all tests in a class have run
		//[ClassCleanup()]
		//public static void MyClassCleanup()
		//{
		//}
		//
		//Use TestInitialize to run code before running each test
		//[TestInitialize()]
		//public void MyTestInitialize()
		//{
		//}
		//
		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//public void MyTestCleanup()
		//{
		//}
		//
		#endregion

		#region KeyedList<TKey, TItem>

		[TestMethod()]
		public void KeyedListConstructorTest()
		{
			IEqualityComparer<string> comparer = StringComparer.OrdinalIgnoreCase;			
			GetKeyForItemDelegate<string, DummyClass> keyForItemDelegate = (x => x.MyKey);
			int dictionaryCreationThreshold = 0;

			KeyedList<string, DummyClass> target = new KeyedList<string, DummyClass>(
				comparer, keyForItemDelegate, dictionaryCreationThreshold);

			target.Add(new DummyClass("abc", "name abc"));
			target.Add(new DummyClass("def", "name def"));

			// test both IEqualityComparer and GetKeyForItemDelegate

			DummyClass result = target["ABc"];
			Assert.IsNotNull(result);
			Assert.AreEqual(result.MyName, "name abc");

			DummyClass result2 = target["deF"];
			Assert.IsNotNull(result2);
			Assert.AreEqual(result2.MyName, "name def");


			try
			{
				KeyedList<string, DummyClass> target2 = new KeyedList<string, DummyClass>();
				Assert.Fail("An exception should have been trown since the DummyClass does not provide any Key info");
			}
			catch(Exception ex)
			{
				TestContext.WriteLine("Expected Exception: {0}", ex.Message);
			}
		}

		[TestMethod()]
		public void TryGetValueTest()
		{
			KeyedList<string, KeyedTestClass> target = new KeyedList<string, KeyedTestClass>();
			string key = "123abc";
			KeyedTestClass valueExpected = new KeyedTestClass(key, "value_123abc");
			target.Add(valueExpected);


			KeyedTestClass value;
			bool expected;
			bool actual;


			expected = false;
			actual = target.TryGetValue("123456", out value);
			Assert.AreEqual(null, value);
			Assert.AreEqual(expected, actual);


			expected = true;
			actual = target.TryGetValue(key, out value);
			Assert.AreEqual(valueExpected, value);
			Assert.AreEqual(expected, actual);

			//indexer test
			Assert.AreEqual(target[key], value);

			try
			{
				KeyedTestClass class1 = target["asf223#2"];
				Assert.Fail("KeyedList should fail with a non existing key");
			}
			catch(Exception ex)
			{
				TestContext.WriteLine("Expected Exception: {0}", ex.Message);
			}


		}

		[TestMethod()]
		public void CheckRepressedKeyDelegateExceptionTest()
		{

			KeyedList<string, AttributedTestClass> target1 = new KeyedList<string, AttributedTestClass>();
			KeyedList<string, KeyedByParentClass> target2 = new KeyedList<string, KeyedByParentClass>();
			KeyedList<string, KeyedTestClass> target3 = new KeyedList<string, KeyedTestClass>();

			try
			{
				KeyedList<string, DummyClass> target4 = new KeyedList<string, DummyClass>();
				Assert.Fail("An exception should have been trown since the DummyClass does not provide any Key info");
			}
			catch(Exception ex)
			{
				TestContext.WriteLine("Expected Exception: {0}", ex.Message);
			}

			KeyedList<string, DummyClass> target5 = new KeyedList<string, DummyClass>(x=> x.MyKey);

		}
		
		[TestMethod()]
		public void AddRangeTest()
		{
			List<KeyedTestClass> list = new List<KeyedTestClass>();
			list.Add(new KeyedTestClass("123abc", "value_123abc"));
			list.Add(new KeyedTestClass("456abc", "value_456abc"));
			list.Add(new KeyedTestClass("789abc", "value_789abc"));
			list.Add(new KeyedTestClass("123def", "value_123def"));
			list.Add(new KeyedTestClass("456def", "value_456def"));
			list.Add(new KeyedTestClass("789def", "value_789def"));
				
			
			KeyedList<string, KeyedTestClass> target = new KeyedList<string, KeyedTestClass>();
			target.AddRange(list);
			Assert.AreEqual(6, target.Count);

			KeyedTestClass actual = target["789abc"];
			Assert.IsNotNull(actual);

			Assert.AreEqual("value_789abc", actual.MyName);

		}

		[TestMethod()]
		[DeploymentItem("CodePlex.KeyedList.dll")]
		public void GetKeyForItemTest()
		{
			KeyedList_Accessor<string, DummyClass> target = new KeyedList_Accessor<string, DummyClass>(x=> x.MyKey);

			DummyClass item = new DummyClass("key123", "name");
			string expected = "key123"; 
			string actual;
			actual = target.GetKeyForItem(item);
			Assert.AreEqual(expected, actual);

		}

		#endregion

		#region ICollection Tests

		[TestMethod()]
		public void ContainsTest()
		{
			KeyedList<string, KeyedTestClass> target = new KeyedList<string, KeyedTestClass>();
			target.Add(new KeyedTestClass("123abc", "value_123abc"));
			target.Add(new KeyedTestClass("456abc", "value_456abc"));
			target.Add(new KeyedTestClass("789abc", "value_789abc"));
			target.Add(new KeyedTestClass("123def", "value_123def"));
			target.Add(new KeyedTestClass("456def", "value_456def"));
			target.Add(new KeyedTestClass("789def", "value_789def"));

			KeyedTestClass item = new KeyedTestClass("123def", "value_123def");
			KeyedTestClass itemInCollection = target["123def"];

			Assert.AreNotEqual(item, itemInCollection);
			Assert.IsFalse(object.ReferenceEquals(item, itemInCollection));

			bool expected;
			bool actual;

			expected = true;
			actual = target.Contains(item);
			Assert.AreEqual(expected, actual);

			expected = true;
			actual = target.Contains(itemInCollection);
			Assert.AreEqual(expected, actual);

			expected = true;
			actual = target.Contains("123def");
			Assert.AreEqual(expected, actual);

			// remove
			expected = true;
			actual = target.Remove("123def");
			Assert.AreEqual(expected, actual);

			// remove
			expected = false;
			actual = target.Remove(itemInCollection);
			Assert.AreEqual(expected, actual);
			

			expected = false;
			actual = target.Contains(item);
			Assert.AreEqual(expected, actual);

			expected = false;
			actual = target.Contains(itemInCollection);
			Assert.AreEqual(expected, actual);

			expected = false;
			actual = target.Contains("123def");
			Assert.AreEqual(expected, actual);

			// add it back
			target.Add(item);


			expected = true;
			actual = target.Contains(item);
			Assert.AreEqual(expected, actual);

			expected = true;
			actual = target.Contains(itemInCollection);
			Assert.AreEqual(expected, actual);

			expected = true;
			actual = target.Contains("123def");
			Assert.AreEqual(expected, actual);

		}

		[TestMethod()]
		public void IndexOfTest()
		{

			KeyedList<string, KeyedTestClass> target = new KeyedList<string, KeyedTestClass>();
			target.Add(new KeyedTestClass("123abc", "value_123abc"));
			target.Add(new KeyedTestClass("456abc", "value_456abc"));
			target.Add(new KeyedTestClass("789abc", "value_789abc"));
			target.Add(new KeyedTestClass("123def", "value_123def"));
			target.Add(new KeyedTestClass("456def", "value_456def"));
			target.Add(new KeyedTestClass("789def", "value_789def"));


			string key = "456def";
			int expectedIndex = 4;
			int actualIndex;
			actualIndex = target.IndexOf(key);
			Assert.AreEqual(expectedIndex, actualIndex);

			KeyedTestClass itemByIndex = target[expectedIndex];
			KeyedTestClass itemByKey = target[key];

			Assert.AreEqual(itemByIndex, itemByKey);
			Assert.IsTrue(object.ReferenceEquals(itemByIndex, itemByKey));


			actualIndex = target.IndexOf(itemByKey);
			Assert.AreEqual(expectedIndex, actualIndex);

		}

		#endregion

		#region List<> tests

		//[TestMethod()]
		//public void ConvertAllTest()
		//{
		//    //KeyedList<TKey, TItem> target = new KeyedList<TKey, TItem>(); // TODO: Initialize to an appropriate value
		//    //Converter<TItem, TOutput> converter = null; // TODO: Initialize to an appropriate value
		//    //List<TOutput> expected = null; // TODO: Initialize to an appropriate value
		//    //List<TOutput> actual;
		//    //actual = target.ConvertAll<TOutput>(converter);
		//    //Assert.AreEqual(expected, actual);
		//    //Assert.Inconclusive("Verify the correctness of this test method.");
		//}

		//[TestMethod()]
		//public void ExistsTest()
		//{
		//    //KeyedList<TKey, TItem> target = new KeyedList<TKey, TItem>(); // TODO: Initialize to an appropriate value
		//    //Predicate<TItem> match = null; // TODO: Initialize to an appropriate value
		//    //bool expected = false; // TODO: Initialize to an appropriate value
		//    //bool actual;
		//    //actual = target.Exists(match);
		//    //Assert.AreEqual(expected, actual);
		//    //Assert.Inconclusive("Verify the correctness of this test method.");
		//}

		//[TestMethod()]
		//public void FindTest()
		//{
		//    //KeyedList<TKey, TItem> target = new KeyedList<TKey, TItem>(); // TODO: Initialize to an appropriate value
		//    //Predicate<TItem> match = null; // TODO: Initialize to an appropriate value
		//    //TItem expected = default(TItem); // TODO: Initialize to an appropriate value
		//    //TItem actual;
		//    //actual = target.Find(match);
		//    //Assert.AreEqual(expected, actual);
		//    //Assert.Inconclusive("Verify the correctness of this test method.");
		//}

		//[TestMethod()]
		//public void ToArrayTest()
		//{
		//    //KeyedList<TKey, TItem> target = new KeyedList<TKey, TItem>(); // TODO: Initialize to an appropriate value
		//    //TItem[] expected = null; // TODO: Initialize to an appropriate value
		//    //TItem[] actual;
		//    //actual = target.ToArray();
		//    //Assert.AreEqual(expected, actual);
		//    //Assert.Inconclusive("Verify the correctness of this test method.");
		//}

		//[TestMethod()]
		//public void TrueForAllTest()
		//{
		//    //KeyedList<TKey, TItem> target = new KeyedList<TKey, TItem>(); // TODO: Initialize to an appropriate value
		//    //Predicate<TItem> match = null; // TODO: Initialize to an appropriate value
		//    //bool expected = false; // TODO: Initialize to an appropriate value
		//    //bool actual;
		//    //actual = target.TrueForAll(match);
		//    //Assert.AreEqual(expected, actual);
		//    //Assert.Inconclusive("Verify the correctness of this test method.");
		//}

		//[TestMethod()]
		//public void FindAllTest()
		//{
		//    //KeyedList<TKey, TItem> target = new KeyedList<TKey, TItem>(); // TODO: Initialize to an appropriate value
		//    //Predicate<TItem> match = null; // TODO: Initialize to an appropriate value
		//    //List<TItem> expected = null; // TODO: Initialize to an appropriate value
		//    //List<TItem> actual;
		//    //actual = target.FindAll(match);
		//    //Assert.AreEqual(expected, actual);
		//    //Assert.Inconclusive("Verify the correctness of this test method.");
		//}

		#endregion

		#region KeyedList<TKey1, TKey2, TItem>

		[TestMethod()]
		public void ItemTest2()
		{
			
			KeyedList<string, int, KeyedTestClass2> target = new KeyedList<string, int, KeyedTestClass2>();
			target.Add(new KeyedTestClass2("abc", 1, "value 1"));
			target.Add(new KeyedTestClass2("abc", 2, "value 2"));
			target.Add(new KeyedTestClass2("def", 1, "value 3"));
			target.Add(new KeyedTestClass2("def", 2, "value 4"));

			string key1 = "def";
			int key2 = 1;

			KeyedTestClass2 actual;
			actual = target[key1, key2];
			Assert.IsNotNull(actual);
			Assert.AreEqual("value 3", actual.Value);

		}

		[TestMethod()]
		public void TryGetValueTest2()
		{

			string key1 = "abc";
			int key2 = 2;
			KeyedTestClass2 valueExpected = new KeyedTestClass2(key1, key2, "value 2"); 
			KeyedList<string, int, KeyedTestClass2> target = new KeyedList<string, int, KeyedTestClass2>();
			target.Add(new KeyedTestClass2("abc", 1, "value 1"));
			target.Add(valueExpected);
			target.Add(new KeyedTestClass2("def", 1, "value 3"));
			target.Add(new KeyedTestClass2("def", 2, "value 4"));
			
			KeyedTestClass2 value;
			bool expected = true; 
			bool actual;
			actual = target.TryGetValue(key1, key2, out value);
			
			Assert.AreEqual(expected, actual);
			Assert.AreEqual(valueExpected, value);
			Assert.AreEqual("value 2", value.Value);

		}

		[TestMethod()]
		public void RemoveTest2()
		{

			string key1 = "abc";
			int key2 = 2;
			KeyedTestClass2 value = new KeyedTestClass2(key1, key2, "value 2");
			KeyedList<string, int, KeyedTestClass2> target = new KeyedList<string, int, KeyedTestClass2>();
			target.Add(new KeyedTestClass2("abc", 1, "value 1"));
			target.Add(value);
			target.Add(new KeyedTestClass2("def", 1, "value 3"));
			target.Add(new KeyedTestClass2("def", 2, "value 4"));
			
			bool expected = true;
			bool actual;
			actual = target.Remove(key1, key2);
			Assert.AreEqual(expected, actual);

			expected = false;
			actual = target.Contains(key1, key2);
			Assert.AreEqual(expected, actual);

			target.Add(new KeyedTestClass2(key1, key2, "value 5"));
			expected = true;
			actual = target.Contains(key1, key2);
			Assert.AreEqual(expected, actual);

		}

		[TestMethod()]
		public void ContainsTest2()
		{

			string key1 = "abc";
			int key2 = 2;
			KeyedTestClass2 value = new KeyedTestClass2(key1, key2, "value 2");
			KeyedList<string, int, KeyedTestClass2> target = new KeyedList<string, int, KeyedTestClass2>();
			target.Add(new KeyedTestClass2("abc", 1, "value 1"));
			target.Add(value);
			target.Add(new KeyedTestClass2("def", 1, "value 3"));
			target.Add(new KeyedTestClass2("def", 2, "value 4"));


			bool expected;
			bool actual;

			expected = true;
			actual = target.Contains(key1, key2);
			Assert.AreEqual(expected, actual);


			expected = false;
			actual = target.Contains("def", 3);
			Assert.AreEqual(expected, actual);

			expected = true;
			actual = target.Contains("abc", 1);
			Assert.AreEqual(expected, actual);


		}

		#endregion

	}
}
